package uk.ac.aber.paws.client.net;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Hashtable;
import java.util.Vector;
import java.util.logging.Level;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import uk.ac.aber.paws.client.core.Initiator;
import uk.ac.aber.paws.client.core.PAWSClient;
import uk.ac.aber.paws.client.db.DBCall;
import static uk.ac.aber.paws.client.constants.NetworkConstants.*;

/**
 * @author Rob Johnson, Aberystwyth University
 * @email rob.johnson@aber.ac.uk
 * @date 16th August 2011
 * 
 * SendMessage.java
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

public class SendMessage {
	
	public static void sleepMe(int port) {
		
		SSLSocket socket = null;
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
			
			final String[] enabledCipherSuites = {"SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
			socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(SLEEP_COMMAND); 
			                       
		}
		catch (java.net.SocketTimeoutException ex) {
			ex.printStackTrace();
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * Sends a message to the service so that the auto logout is recorded in the database.
	 * @param port
	 */
	public static boolean sendAutoLogoutMessage(int port) {
		
		SSLSocket socket = null;
		boolean result = true;
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
			
			final String[] enabledCipherSuites = {"SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
			socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(AUTO_LOGOFF_MESSAGE); 
			oos.writeObject(System.getenv("USERNAME").toUpperCase());
			                       
		}
		catch (java.net.SocketTimeoutException ex) {
			ex.printStackTrace();
			result = false;
		}
		catch (Exception ex) {
			ex.printStackTrace();
			result = false;
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		return result;
	}

	/**
	 * Sends a message to the service so that the auto logout is recorded in the database.
	 * @param port
	 */
	public static boolean requestComputerRegStatus(int port, String computerName) {
		
		SSLSocket socket = null;
		boolean result = true;
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
			
			final String[] enabledCipherSuites = {"SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
			socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(AUTO_LOGOFF_MESSAGE); 
			oos.writeObject(System.getenv("USERNAME").toUpperCase());
			                       
		}
		catch (java.net.SocketTimeoutException ex) {
			ex.printStackTrace();
			result = false;
		}
		catch (Exception ex) {
			ex.printStackTrace();
			result = false;
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		return result;
	}
	
	public static boolean sendPendriveMessage(int port) {
		
		SSLSocket socket = null;
		boolean result = true;
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
			
			final String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
			socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(PENDRIVE_MESSAGE); 
			oos.writeObject(System.getenv("USERNAME").toUpperCase());
			                       
		}
		catch (java.net.SocketTimeoutException ex) {
			ex.printStackTrace();
			result = false;
		}
		catch (Exception ex) {
			ex.printStackTrace();
			result = false;
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		return result;
	}
	
	public static Vector<Hashtable<String,Object>> requestLoginInfo(int port) {
		
		SSLSocket socket = null;
		boolean result = true;
		
		Vector<Hashtable<String,Object>> response = null;
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
			
			final String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
		    socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(REQUEST_GET_LOGININFO); 
			                      
			ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
			
			response = (Vector<Hashtable<String,Object>>)ois.readObject();
		}
		catch (java.net.SocketTimeoutException ex) {
			result = false;
		}
		catch (Exception ex)  {
			result = false;
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		return response;
	}

	
	public static boolean sendIdleTimeMessage(long idle, int port, String userName) {
		
		SSLSocket socket = null;
		boolean result = true;
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
			
			final String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
		    socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(REPORT_IDLE_TIME); 
			oos.writeObject(new Long(idle));
			oos.writeObject(userName);
			                      
		}
		catch (java.net.SocketTimeoutException ex) {
			result = false;
		}
		catch (Exception ex)  {
			result = false;
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		return result;
	}

	public static Hashtable requestInformation(int port) {
		
		Hashtable response = null;
		
		SSLSocket socket = null;
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
			
			final String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
			socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(REQUEST_CLIENT_INFORMATION); 
			        
			ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());

			response = (Hashtable)ois.readObject();
		}
		catch (java.net.SocketTimeoutException ex) {
			ex.printStackTrace();
		}
		catch (Exception ex)  {
			ex.printStackTrace();
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
			
		return response;
	}


	public static Object sendDBCall(DBCall dbCall) {
		
		SSLSocket socket = null;
		
		int networkWaitTime = 20;
		
		try { 
			networkWaitTime = Integer.parseInt((String)PAWSClient.getConfig().getProperty("app.main.net.networkconnectwaittime"));
		}
		catch (Exception ex) { 
			Initiator.LOG_FILE.log(Level.ALL,"Cannot find config item: app.main.net.networkconnectwaittime, using default value of 20 seconds");
		}
		
		try {
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			
			Initiator.LOG_FILE.log(Level.ALL,"Secure Comms Port: "+PAWSClient.getConfig().getProperty("app.main.net.secureservercommsport"));
			
			boolean connected = false;
			int count = 0;
			
			// try for 20 seconds until network appears to be up...
			while (!connected && count < networkWaitTime) {
				try {
					socket = (SSLSocket)SSLSocketfactory.createSocket(PAWSClient.getConfig().getProperty("app.main.net.servercommsaddress"),Integer.parseInt(PAWSClient.getConfig().getProperty("app.main.net.secureservercommsport")));
					connected = true;
				}
				catch (UnknownHostException ex) {
					count++;
					Thread.currentThread().sleep(1000);
					Initiator.LOG_FILE.log(Level.ALL,"Problems connecting to server, attempt "+count+" of "+networkWaitTime);
				}
			}
			
			
			// if a successful connection...
			if (connected && socket != null) {
			
				final String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
			    socket.setEnabledCipherSuites(enabledCipherSuites);
			    
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
				oos.writeObject(dbCall); 
					
				if (dbCall.getResponseRequired()) {
					
					// read the database call info from the socket
					ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
	
					DBCall response = (DBCall)ois.readObject();
					
					return response;
				}
				else {
					ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
					
					Boolean response = (Boolean)ois.readObject();
					
					return response;
				}
			}
			
		}
		catch (java.net.SocketTimeoutException ex) {
			dbCall = null;
			ex.printStackTrace();
		}
		catch (ConnectException ex) {
			dbCall = null;
			ex.printStackTrace();
		}
		catch (Exception ex) {
			dbCall = null;
			ex.printStackTrace();
		}
		finally {
			
			dbCall = null;
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		return dbCall;
	}

	public static boolean requestRestart(int port) {
		
		SSLSocket socket = null;
		boolean result = true;
		
		try {
			
			SSLSocketFactory SSLSocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			
			socket = (SSLSocket)SSLSocketfactory.createSocket("127.0.0.1",port);
		
			final String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
		    socket.setEnabledCipherSuites(enabledCipherSuites);
		    
			socket.setSoTimeout(2000);
			
			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());             
			oos.writeObject(REQUEST_RESTART_SERVICE); 
			                       
			socket.close();
			
		}
		catch (java.net.SocketTimeoutException ex) {
			result = false;
		}
		catch (Exception ex)  {
			result = false;
		}
		finally {
			
			if (socket != null) {
				try {
					socket.close();
				} 
				catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}	
		return result;
	}

}
